package com.dd.front.service.impl;

import cn.dev33.satoken.stp.SaTokenInfo;
import cn.dev33.satoken.stp.StpUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.dd.common.config.GlobalConfig;
import com.dd.common.dto.user.UserLoginDTO;
import com.dd.common.entity.User;
import com.dd.common.enums.ErrorEnum;
import com.dd.common.exception.BusinessException;
import com.dd.common.mapper.UserMapper;
import com.dd.common.utils.IpUtils;
import com.dd.common.utils.StrGenerator;
import com.dd.common.vo.UserLoginVO;
import com.dd.front.service.LoginService;
import org.springframework.beans.BeanUtils;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.Objects;

/**
 * @author cheng
 */
@Service
public class LoginServiceImpl implements LoginService {

    @Resource
    private UserMapper userMapper;
    @Override
    public UserLoginVO accountLogin(UserLoginDTO dto) {
        String rawPassword = dto.getPassword();
        String username = dto.getUsername();
        String email = dto.getEmail();
        String phone = dto.getPhone();

        String ip = IpUtils.getIp();

        // 1. 按优先级查找用户
        User user = null;

        // 按优先级查找用户
        if (username != null && !username.trim().isEmpty()) {
            user = userMapper.selectOne(new LambdaQueryWrapper<User>().eq(User::getUsername, username));
        }

        if (user == null && email != null && !email.trim().isEmpty()) {
            user = userMapper.selectOne(new LambdaQueryWrapper<User>().eq(User::getEmail, email));
        }

        if (user == null && phone != null && !phone.trim().isEmpty()) {
            user = userMapper.selectOne(new LambdaQueryWrapper<User>().eq(User::getPhone, phone));
        }

        if (user == null) {
            throw new BusinessException(ErrorEnum.USER_NOT_FOUND);
        }

        if (!Objects.equals(user.getStatus(), GlobalConfig.STATUS_ENABLE)) {
            throw new BusinessException(ErrorEnum.USER_DISABLED);
        }

        if (!user.getPassword().equals(StrGenerator.makeMd5(rawPassword))) {
            throw new BusinessException(ErrorEnum.PASSWORD_ERROR);
        }

        // sa-token 登录
        StpUtil.login(user.getId());
        // sa-token 有三种 Session 模型：account-session token-session custom-session
        // account-session: 对应账号范围，比如：PC、手机多设备同账号登录，它们共享同一个 account-session
        // token-session: 对应Token范围，比如同样是多设备登录，但每个设备的token肯定都不一样，所以每个设备都有各自隔离的 token-session
        // Custom-Session不依赖特定的 账号id 或者 token，而是依赖于你提供的SessionId
        StpUtil.getSession().set(GlobalConfig.CURRENT_USER, user);
        SaTokenInfo tokenInfo = StpUtil.getTokenInfo();

        // 记录登录IP和时间
        this.updateLoginInfo(user.getId(), ip);

        UserLoginVO vo = new UserLoginVO();
        BeanUtils.copyProperties(user, vo);
        vo.setToken(tokenInfo.getTokenValue());
        return vo;
    }

    /**
     * 更新登录信息，异步执行
     */
    @Async
    public void updateLoginInfo(Long userId, String ip) {
        userMapper.update(null, new LambdaUpdateWrapper<User>()
                .eq(User::getId, userId)
                .set(User::getLastLoginTime, LocalDateTime.now())
                .set(User::getLastLoginIp, ip));
    }
}
